#include <stdint.h>
#include <stdio.h>

#include "appdefs.h"
#include "platform_config.h"
#include "stm32f10x.h"
#include "hw_config.h"

#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>

#include "lib_dbg.h"
#include "tasks/eeprom.h"
#include "tasks/tsk_lcd.h"
#include "tasks/tsk_adc.h"
#include "tasks/tsk_main.h"

static void prvSetupHardware();

#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  ____     ____    ____
-|_R1_|---|_R2_|--|_R3_|--
R1 = 13k, R2 = 680, R3 = 1.5
I = 0.235*(R1+R2)/(R1*R3) - U*R2/(R1*R3)
I(mA) = 164.9 - 0.0349*U(mV)
Imin = 50 mA, Imax = 165 mA.
*/

#ifdef DEBUG
uint8_t eeBuffer[1024];
volatile uint16_t DataRead = 0;
#endif

portTASK_FUNCTION_PROTO( vLED, pvParameters );

//--------------------------------------------------------------------------
int main()
{
#ifdef DEBUG
	debug();
#endif

	SystemStartup();
	prvSetupHardware();
	sEE_Init();

#ifdef DEBUG
	memset( eeBuffer, 0, sizeof( eeBuffer ) );
	DataRead = 1024;
	sEE_ReadBuffer( eeBuffer, 0, ( uint16_t * ) &DataRead );
#endif

	printf( "H\n" );
	printf( "Application starting\n" );
	
	vStartLCD( 4 );
	vStartMain( 0 );
	xTaskCreate( vLED, ( signed portCHAR * ) "led", configMINIMAL_STACK_SIZE, NULL, 0, NULL );
	vTaskStartScheduler();
	
	for( ; ; )
	{
	}
	return 0;
}

portTASK_FUNCTION( vLED, pvParameters )
{
( void ) pvParameters;

portTickType xLaskWeakTime = xTaskGetTickCount();
	for( ;; )
	{
		GPIO_WriteBit( LED_PORT, LED_RED_PIN,
				( BitAction ) ( 1 - GPIO_ReadOutputDataBit( LED_PORT, LED_RED_PIN ) ) );

		vTaskDelayUntil( &xLaskWeakTime, 500 );
	}

}

void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
{
	/* This function will get called if a task overflows its stack.   If the
	parameters are corrupt then inspect pxCurrentTCB to find which was the
	offending task. */

	( void ) pxTask;
	( void ) pcTaskName;

	for( ;; );
}

/*
 * Configure clocks of peripheral
 */
static void RCC_Configuration()
{
	// GPIO and AFIO Clocks
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | \
							RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE );

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE ); // USART1 (PA9, PA10)
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE );
}


static void GPIO_Configuration()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// All pins as input
	GPIO_InitStructure.GPIO_Pin 		= GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &GPIO_InitStructure );
	GPIO_Init( GPIOB, &GPIO_InitStructure );
	GPIO_Init( GPIOC, &GPIO_InitStructure );

	// USART1 Rx (PA10)
	GPIO_InitStructure.GPIO_Pin		= GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_IN_FLOATING;
	GPIO_Init( GPIOA, &GPIO_InitStructure );

	// USART1 Tx (PA9)
	GPIO_InitStructure.GPIO_Pin 		= GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_AF_PP;
	GPIO_Init( GPIOA, &GPIO_InitStructure );

	// DAC
	GPIO_InitStructure.GPIO_Pin 		= DAC_PIN_1 | DAC_PIN_2;
	GPIO_InitStructure.GPIO_Mode	= DAC_GPIO_MODE;
	GPIO_Init( DAC_PORT, &GPIO_InitStructure );

	GPIO_InitStructure.GPIO_Pin 		= LED_BLUE_PIN | LED_RED_PIN;
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_Out_PP;
	GPIO_Init( LED_PORT, &GPIO_InitStructure );
	GPIO_SetBits( LED_PORT, LED_BLUE_PIN | LED_RED_PIN );
}

static void prvSetupHardware()
{
	RCC_Configuration();
	GPIO_Configuration();

USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init( USART1, &USART_InitStructure );
	USART_Cmd( USART1, ENABLE );

	// Default DAC Values
DAC_InitTypeDef DAC_InitStructure;
	DAC_InitStructure.DAC_Trigger = DAC_Trigger_Software;
	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_Init( DAC_Channel_1, &DAC_InitStructure );
	DAC_Init( DAC_Channel_2, &DAC_InitStructure );
	DAC_Cmd( DAC_Channel_1, ENABLE );
	DAC_Cmd( DAC_Channel_2, ENABLE );

	// DAC maximum values
	DAC_SetDualChannelData( DAC_Align_12b_R, 0, 0 );
	DAC_DualSoftwareTriggerCmd( ENABLE );
	DAC_SetDualChannelData( DAC_Align_12b_R, 3500, 3500 );
	DAC_DualSoftwareTriggerCmd( ENABLE );
}

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(USART1, (uint8_t) ch);

  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
  {}

  return ch;
}

